package roborally.util;

import roborally.*;
import roborally.Pieces.*;
import be.kuleuven.cs.som.annotate.*;
/**
 * This is an enum representing basic boolean methods for the program.

 * @version 3.0
 * @author 	Bart Opsomer 2de Bachelor Ingenieurswetenschappen Electrotechniek-Computerwetenschappen 
 * 		   	Peter Opsomer 1ste Master Wiskundige IngenieursTechnieken
 */
public enum CommandWordsCondition{
	// All the possible conditions, with their implementation
	TRUE("true", new  Class[]{Robot.class}) 	{
		@Override
		public boolean evaluate(Object[] args) {
			return true;
		}
	}
	, ENERGYATLEAST("energy-at-least",new  Class[]{Robot.class, Integer.class}) {
		@Override
		public boolean evaluate(Object[] args) {
			Class<? extends Object> class1 = args[0].getClass();
			Class<? extends Object> class2 = args[1].getClass();
			if(class1 == this.arguments[0] && class2 == this.arguments[1]) {
				Robot robot = (Robot) args[0];
				int integer = (int) (Integer)args[1];
				return robot.getEnergy().getAmountInWattSeconds() >= integer;
			}
			return false;
		}
	}
	, ATITEM("at-item", new  Class[]{Robot.class}) {
		@Override
		public boolean evaluate(Object[] args) {
			if(args[0].getClass() == this.arguments[0]) {
				Robot robot = (Robot) args[0];
				Position position = robot.getPosition();
				Board board = position.getBoard();
				return board.getItemsAt(position) != null && !board.getItemsAt(position).isEmpty();
			}
			return false;
		}
	}
	, CANHITROBOT("can-hit-robot", new  Class[]{Robot.class}) {
		@Override
		public boolean evaluate(Object[] args) {
			if(args[0].getClass() == this.arguments[0]) {
				Robot robot = (Robot) args[0];
				return robot.getPosition().getBoard().robotInRangeOf(robot);
			}
			return false;
		}
	}
	, WALL("wall", new  Class[]{Robot.class}) {
		@Override
		public boolean evaluate(Object[] args) {
			if(args[0].getClass() == this.arguments[0]) {
				Robot robot = (Robot) args[0];
				Position position = robot.getPosition();
				Board board = position.getBoard();
				PositionWithOrientation positionWithOrientation = 
						PositionWithOrientation.getPWO(position.getX(), position.getY(),board, Orientation.RIGHT);
				PositionWithOrientation nextPositionWithOrientation = positionWithOrientation.nextPosition();
				return board.getWallAt(nextPositionWithOrientation.getPosition()) != null;
			}
			return false;
		}
	}
	;
	// The array of classes in the order, that is necessary for its evaluate method 
	protected final Class<?>[] arguments;
	// The textual representation of the enum
	protected String text;
	/**
	 * Make a newCommandWordsCondition from a String, only used to initialize this enum, so no exceptions if the EnergyUnit doesn't exist yet
	 * @param word the String to make the CommandWordsCondition from
	 * @post | new.getText().equals(word)
	 */
	@Raw
	CommandWordsCondition(String word,Class<?>[] arguments) throws IllegalStateException{
		this.text = word;
		this.arguments = arguments;
	}
	/**
	 * @return the text of this CommandWordsCondition
	 */
	@Basic
	public String getText() {
		return this.text;
	}
	/**
	 * @return the classes of the argument of the evaluate method of this CommandWordsCondition
	 */
	@Basic
	public Class<?>[] getArguments() {
		return this.arguments;
	}
	/**
	 * Get the CommandWordsCondition that the given String represents.
	 * 
	 * @param condition the String representing an CommandWordsCondition
	 * @return | result == null || result.getText().equals(condition)
	 */
	public static CommandWordsCondition fromString(String condition) {
		if (condition != null) {
			for (CommandWordsCondition c : CommandWordsCondition.values()) {
				if (condition.equals(c.getText())) {
					return c;
				}
			}
		}
		return null;
	}
	/**
	 * the function that is defined by the enum
	 * @param args the arguments of this method
	 * @return the result of the boolean function of the enum
	 */
	public abstract boolean evaluate(Object[] args);
	
}
